洛谷题解 P2184 【贪婪大陆】

题目大意

给出每种地雷布置的区间,求某一区间的地雷总数

思路

1.(错误示例)用线段树维护区间地雷个数及区间单点地雷数最大值,每次给某一区间地雷均+1,每次再查询区间中单个点最大地雷数(因为每次铺的地雷都不一样)

缺陷:可能同一区间中存在地雷种类不同(例如存在两点地雷数相同,但是铺的地雷不完全相同)

2.用线段树维护区间铺地雷的起点及终点个数,运用差分的思想,区间地雷种类数=[1,r]区间的起点个数-[1,l-1]区间的终点个数

例:设1为起点 2为终点 0为非终点起点

1
2
1 1 0 1 0 2 1 1 0 1  2  0  2  1  2  0  2  0  2  0  0  0  0  2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

[4,12]区间内的地雷总数为 6-0=6个

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

struct node
{
int l, r;
long long f, ws, we;//ws 起点 we 终点
} tree[400010];

int n, m;
long long ans = 0, ansq, anst;

void build(int p, int l, int r)
{
tree[p].l = l, tree[p].r = r;
if (l == r)
{
tree[p].ws = 0;
tree[p].we = 0;
return;
}
int mid = l + ((r - l) >> 1);
build(p << 1, l, mid);
build((p << 1) | 1, mid + 1, r);
tree[p].ws = tree[p << 1].ws + tree[(p << 1) | 1].ws;
tree[p].we = tree[p << 1].we + tree[(p << 1) | 1].we;
// tree[p].maxn = max(tree[p<<1].maxn,tree[(p<<1)|1].maxn); 错误思路
}

void add_point(int p, int add_p, int k, int opts)
{
if (tree[p].l == tree[p].r && tree[p].l == add_p)
{
if (opts == 1)
{
tree[p].ws++;
}
else
{
tree[p].we++;
}
return;
}

int mid = tree[p].l + ((tree[p].r - tree[p].l) >> 1);
if (add_p <= mid)
{
add_point(p << 1, add_p, k, opts);
}
if (add_p > mid)
{
add_point((p << 1) | 1, add_p, k, opts);
}
tree[p].ws = tree[p << 1].ws + tree[(p << 1) | 1].ws;
tree[p].we = tree[p << 1].we + tree[(p << 1) | 1].we;
}

void query_interval(int p, int add_l, int add_r, int opts)
{
if (tree[p].l >= add_l && tree[p].r <= add_r)
{
if (opts == 1)
{
ans = ans + tree[p].ws;
}
else
{
ans = ans + tree[p].we;
}

// ans = ans + tree[p].ls + tree[p].rs;
return;
}

int mid = tree[p].l + ((tree[p].r - tree[p].l) >> 1);
if (add_l <= mid)
{
query_interval(p << 1, add_l, add_r, opts);
}
if (add_r > mid)
{
query_interval((p << 1) | 1, add_l, add_r, opts);
}
}

int main()
{
scanf("%d%d", &n, &m);
build(1, 1, n);
for (int a = 1; a <= m; ++a)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
if (x == 1)
{
add_point(1, y, 1, 1);
add_point(1, z, 1, 2);
}
if (x == 2)
{
ans = 0;
query_interval(1, 1, z, 1);
ansq = ans;//ansq起点个数
ans = 0;
query_interval(1, 1, y - 1, 2);
anst = ans;
printf("%lld\n", ansq - anst);
}
}
return 0;
}

P2184